package view;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.rmi.RemoteException;

import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JFrame;

import server.FirewallException;
import controller.FirewallSession;
import server.NotExpertException;
import server.ReadWriteException;
import server.RulesTableType;

/**
 * Class is responsible for advanced user rules frame.
 * Frame contains all elements that are defined in inherited class and only advanced user buttons:
 * 		Add rule
 * 		Edit rule
 * 		Delete rule
 */
public class RulesAdvancedFrame  extends AbstractRulesFrame
{
	/**
	 * Serial version ID - for serialization
	 */
	private static final long serialVersionUID = 9201679036101368799L;
	
	/**
	 * C'tor - Frame with specified controller is created.
	 * @param ui	- the controller for the system actions
	 */
	private RulesAdvancedFrame(FirewallSession ui)
	{
		super(ui);
		setLocationRelativeTo(null);
	}
	
	/**
	 * Returns current frame if exists, else creates and registers it.
	 * @return rules frame
	 */
	public static AbstractRulesFrame getInstance(FirewallSession ui)
	{
		if(currentRulesFrame == null)
		{
			currentRulesFrame = new RulesAdvancedFrame(ui);
		    StatusBar.register(currentRulesFrame);
		}
		else
		{
			RulesAdvancedTable.currentInRulesTable.build();
			RulesAdvancedTable.currentOutRulesTable.build();
		}
		
		return currentRulesFrame;
	}

	/**
	 * Adds buttons for adding, deleting, editing rule
	 * @return group of the advanced special user buttons
	 */
	protected Box getDownRulesButtons()
	{		
		/* Button for adding */	
		Box buttons = Box.createVerticalBox();
	
		JButton add = new JButton("Add Rule");
		add.setToolTipText("Add the new rule to the ruleset");
		add.setMaximumSize(Globals.buttonSize);
		
		buttons.add(add);
		add.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) 
			{
				JFrame frame = new RuleAddFrame(UI);
				frame.setVisible(true);
			}	  
		});
		
		/* Button for deleting */
		JButton delete = new JButton("Delete Rule");
		delete.setToolTipText("Delete the selected rule");
		delete.setMaximumSize(Globals.buttonSize);
		
		buttons.add(delete);		
		delete.addActionListener(new ActionListener() {
			/* delete the selected in tables rule in ruleset, update windows */
			public void actionPerformed(ActionEvent e) 
			{
				/* Find row to delete */
				int[] inSelectedRows = RulesAdvancedTable.currentInRulesTable.getSelectedRows();
				int[] outSelectedRows = RulesAdvancedTable.currentOutRulesTable.getSelectedRows();

				/* No selected row */
				if((inSelectedRows.length + outSelectedRows.length != 1))
				{
			    	ErrorFrame.AddError("You need to select at least one rule to delete in table", 
			    						 RulesAdvancedFrame.currentRulesFrame);
			    	return;
				}

				/* Selected row index */
				int ruleIndex = 0;
				RulesTableType ruleType;
				
				/* Take the relevant row */
				String ruleNumber = "";
				if(inSelectedRows.length == 1)
				{
					ruleIndex = inSelectedRows[0];
					ruleType = RulesTableType.IN;
					ruleNumber = (String)RulesAdvancedTable.currentInRulesTable.getValueAt(ruleIndex,0);
				}
				else /* outSelectedRows.length == 1 */
				{
					ruleIndex = outSelectedRows[0];
					ruleType = RulesTableType.OUT;
					ruleNumber = (String)RulesAdvancedTable.currentOutRulesTable.getValueAt(ruleIndex,0);
				}
				
				/* Row without data */
				if((ruleNumber == null) || (ruleNumber == ""))
				{
					ErrorFrame.AddError("You need to selected filled row in the table to delete", 
   						 				RulesAdvancedFrame.currentRulesFrame);
					return;
				}			
				
				try
				{
					/* Delete row, update tables */
					UI.deleteRule(ruleType, Settings.ruleset, ruleIndex+1);
					RulesAdvancedTable.currentInRulesTable.build();
					RulesAdvancedTable.currentOutRulesTable.build();
				}  catch (RemoteException e1) {
					ErrorFrame.AddError("Connection problems: Failed to delete the rule.", new JFrame());
				} catch (FirewallException e1) {
					ErrorFrame.AddError("Failed to delete the rule:" + e1.getMessage(), new JFrame());
				} catch (ReadWriteException e1) {
					ErrorFrame.AddError("Failed to delete the rule: you have no permissions for the action", 
										new JFrame());
				} catch (NotExpertException e1) {
					/*N/A*/
				}
			}	  
		});
		
		/* Button for editing */
		JButton edit = new JButton("Edit Rule");
		edit.setToolTipText("Edit the selected rule");
		edit.setMaximumSize(Globals.buttonSize);

		buttons.add(edit);
		edit.addActionListener(new ActionListener() {
			/* delete the selected in tables rule in ruleset, add updated one, update windows */
			public void actionPerformed(ActionEvent e) 
			{
				/* Find row to edit */
				int[] inSelectedRows = RulesAdvancedTable.currentInRulesTable.getSelectedRows();
				int[] outSelectedRows = RulesAdvancedTable.currentOutRulesTable.getSelectedRows();
				
				/* delete the selected in tables rule in ruleset, update windows */
				if((inSelectedRows.length + outSelectedRows.length != 1))
				{
			    	ErrorFrame.AddError("You need to select one and only one rule to edit in table", 
			    						 RulesAdvancedFrame.currentRulesFrame);
			    	return;
				}
				
				/* Parameters for rule */
				String[] rule = new String[RulesAdvancedTable.columnNames.length];
				RulesTableType type = null;
				
				/* Selected row index */
				int index = 0;
				
				/* Take the relevant row */
				if(inSelectedRows.length == 1)
				{
					type = RulesTableType.IN;
					index = inSelectedRows[0];
					for(int i = 0; i < rule.length; i++)
					{
						rule[i] = (String) RulesAdvancedTable.currentInRulesTable.getValueAt(index, i);
					}
				}
				else /* outSelectedRows.length == 1 */
				{
					type = RulesTableType.OUT;
					index = outSelectedRows[0];
					for(int i = 0; i < rule.length; i++)
					{
						rule[i] = (String) RulesAdvancedTable.currentOutRulesTable.getValueAt(index, i);
					}					
				}
				
				/* Row without data */
				if((rule[0] == null) || (rule[0] == ""))
				{
					ErrorFrame.AddError("You need to selected filled row in the table", 
   						 				RulesAdvancedFrame.currentRulesFrame);
					return;
				}
				
				/* Show frame */
				JFrame frame = new RuleEditFrame(rule, type, UI);
				frame.setVisible(true);
			}	  
		});
		
		return buttons;	
	}
	
	/**
	 * @param table in/out type
	 * @return table of rules
	 */
	protected AbstractRulesTable getTable(RulesTableType type)
	{
		return new RulesAdvancedTable(type, UI);
	}

	/**
	 * @return the frame title
	 */
	public String getTitle()
	{
		return "Advanced Rules Window";
	}
}
